#include "server.h"
#include "game.h"
#include "entitymanager.h"
#include <QDebug>


EntityManager::EntityManager()
   : mIDCounter(1),
     mSquadIDCounter(0)
{
}


EntityManager::~EntityManager()
{
   qDebug() << "~EntityManager";
   foreach (Entity *e, mEntities)
      delete e;
   mEntities.clear();
}


void EntityManager::setGame(Game *game)
{
   mGame = game;
}


Entity::EntityListType EntityManager::listByType(ENTITY_TYPE type)
{
   Entity::EntityListType ret;
   foreach (Entity *e, mEntities)
   {
      if (e->type() == type || type == ENTITY_ANY)
         ret.push_front(e);
   }
   return ret;
}


Entity* EntityManager::closest(const QVector2D &position, ENTITY_TYPE type)
{
   qreal closestDist = MAX_RANGE;
   Entity *closest = 0;

   foreach (Entity *e, mEntities)
   {
      if (e->active() && (type == ENTITY_ANY || type == e->type()))
      {
         qreal dist = (position - e->position()).length();
         if (dist < closestDist)
         {
            closestDist = dist;
            closest = e;
         }
      }
   }
   return closest;
}


Entity* EntityManager::entityFromID(const qint32 id)
{
   if (mEntities.contains(id))
      return mEntities[id];
   return 0;
}


void EntityManager::tick(const qreal timeDelta)
{
   foreach (Entity *e, mEntities)
   {
      if (e->active())
      {
         e->tick(timeDelta);
         if (mGame->currentTime() >= e->nextThinkTime())
            e->think();
      }
   }
}


void EntityManager::addEntitySquad(const EntitySquadType &squad)
{
   mSquadSizes.insert(squad.id, squad.size);
}

Entity::EntityListType EntityManager::addEntitySquad(const quint32 playerID, const quint32 squadID, const EntityBaseStats &stats, quint32 squadSize)
{
   Entity::EntityListType list;
   for (unsigned int i=0; i<squadSize; ++i)
   {
      Entity *entity = addEntity(playerID, stats);
      entity->setSquadID(squadID);
      list.append(entity);
   }
   mSquadSizes.insert(squadID, squadSize);
   return list;
}


Entity* EntityManager::addEntity(const quint32 playerID, const EntityBaseStats &stats)
{
   Entity *e = 0;
   switch (stats.type)
   {
   case ENTITY_UNIT: e = new Unit(mIDCounter); break;
   case ENTITY_TOWER: e = new Tower(mIDCounter); break;
   case ENTITY_UNITEMITTER: e = new UnitEmitter(mIDCounter);
   default: break;
   }

   if (e)
   {
      e->setBaseStats(stats);
      e->setPlayerID(playerID);
      e->setGame(mGame);
      mEntities.insert(mIDCounter++, e);
      qDebug() << "EntityManager::addEntity id=" << e->id() << "squadID=" << e->squadID();
   }
   return e;
}

bool EntityManager::addEntity(Entity *entity)
{
   entity->setID(mIDCounter);
   entity->setGame(mGame);
   entity->setNextThinkTime(mGame->currentTime());
   mEntities.insert(mIDCounter, entity);
   mIDCounter++;
   return true;
}

void EntityManager::removeEntity(qint32 id)
{
   qDebug() << "EntityManager::removeEntity id=" << id;
   Entity *removedEnt = mEntities.value(id);

   if (removedEnt)
   {
      // NOTE: MUST clear any pointers to this entity or we'll crash next loop iteration
      foreach (Entity *e, mEntities)
      {
         if (e->target() == removedEnt)
            e->setTarget(0);
      }
      delete removedEnt;
   }
   mEntities.remove(id);
   mGame->server->sendEntityRemove(id);
}


void EntityManager::removeInactiveEntities()
{
   foreach (Entity *e, mEntities)
   {
      if (e && !e->active())
      {
         quint32 eid = e->id();
         quint32 squadID = e->squadID();
         quint32 playerID = e->playerID();
         qDebug() << "EntityManager::removeInactiveEntities id=" << eid << "squadID=" << squadID;
         removeEntity(eid);
         // Check if squad was killed
         if (mSquadSizes.contains(squadID))
         {
            mSquadSizes[squadID] -= 1;
            if (mSquadSizes.value(squadID) <= 0)
               mGame->server->sendEntitySquadRemove(squadID, playerID);
         }
      }
   }
}


quint32 EntityManager::uniqueSquadID()
{
   mSquadIDCounter++;
   return mSquadIDCounter;
}
